package com.darkduck.fcap.camera;

import java.io.IOException;

import com.darkduck.fcap.PreferencesActivity;

import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Camera;
import android.os.Build;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.view.SurfaceHolder;


public final class CameraManager {

    private static final String TAG = CameraManager.class.getSimpleName();

    private static CameraManager cameraManager;
    
    static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT
    static {
      int sdkInt;
      try {
        sdkInt = Integer.parseInt(Build.VERSION.SDK);
      } catch (NumberFormatException nfe) {
        // Just to be safe
        sdkInt = 10000;
      }
      SDK_INT = sdkInt;
    }
    
    private final Context context;
    private final CameraConfigurationManager configManager;
    private Camera camera;
    private boolean initialized;
    private boolean previewing;
    private final boolean useOneShotPreviewCallback;
    
    private final PreviewCallback previewCallback;
    private final AutoFocusCallback autoFocusCallback;

    public static void init(Context context) {
        if (cameraManager == null) {
            cameraManager = new CameraManager(context);
        }
    }
    
    private CameraManager(Context context) {

        this.context = context;
        this.configManager = new CameraConfigurationManager(context);

         useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3;
         // 3 = Cupcake

        previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback);
        autoFocusCallback = new AutoFocusCallback();
    }
    
    public static CameraManager get() {
        return cameraManager;
      }
    
    public void openDriver(SurfaceHolder holder) throws IOException {
        if (camera == null) {
          camera = Camera.open();
          if (camera == null) {
            throw new IOException();
          }
        }
        camera.setPreviewDisplay(holder);
        
        if (!initialized) {
            initialized = true;
            configManager.initFromCameraParameters(camera);
          }
          configManager.setDesiredCameraParameters(camera);
        
      }
    
    public void setFrontLightEnable(boolean enable) {       
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        boolean useFrontLight = prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, true);
        if (!useFrontLight) 
            return;
        Camera.Parameters parameters = camera.getParameters();          
        if (enable) {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
        }
        else {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        }
        camera.setParameters(parameters);
    }
  
    /**
     * Closes the camera driver if still in use.
     */
    public void closeDriver() {
        if (camera != null) {
            // FlashlightManager.disableFlashlight();
            camera.release();
            camera = null;

        }
    }
    
    /**
     * Asks the camera hardware to begin drawing preview frames to the screen.
     */
    public void startPreview() {
      if (camera != null && !previewing) {
        camera.startPreview();
        previewing = true;
      }
    }
    
    /**
     * Tells the camera to stop drawing preview frames.
     */
    public void stopPreview() {
      if (camera != null && previewing) {
        if (!useOneShotPreviewCallback) {
          camera.setPreviewCallback(null);
        }
        camera.stopPreview();
        previewCallback.setHandler(null, 0);
        autoFocusCallback.setHandler(null, 0);
        previewing = false;
      }
    }
    
    /**
     * Asks the camera hardware to perform an autofocus.
     *
     * @param handler The Handler to notify when the autofocus completes.
     * @param message The message to deliver.
     */
    public void requestAutoFocus(Handler handler, int message) {
        if (camera != null && previewing) {
            autoFocusCallback.setHandler(handler, message);
            // Log.d(TAG, "Requesting auto-focus callback");
            camera.autoFocus(autoFocusCallback);
        }
    }
    
    public void requestPreviewFrame(Handler handler, int message) {
        if (camera != null && previewing) {
            previewCallback.setHandler(handler, message);
            if (useOneShotPreviewCallback) {
                camera.setOneShotPreviewCallback(previewCallback);
            } else {
                camera.setPreviewCallback(previewCallback);
            }
        }
    }
}
